算法精解----13、二叉搜索树-AVL树

1、树的组织方式:左节点小于根节点,右节点大于根节点。平衡二叉树最坏情况log2 (n)。顺序排列只有单支最坏情况为n。可以采取随机插入等方式解决此问题,其中最好的方法就是 二叉搜索树实现AVL树。

2、AVL树:每个节点额外保存一个平衡因子,值为右子树高度减去左子树高度。插入节点时,AVL树需要自我调整保持所有平衡因子值为-1(左倾斜)、0、+1(右倾斜)。根节点的平衡因子代表整个树的平衡性。

3、实际上红黑树的统计性比AVL树更好。

4、几种其他树:
(1)K叉树:每个节点有多条分支

(2)红黑树:节点有颜色属性,红、黑

(3)Trie树:用来查找变长字符串组合

(4)B、B+、B*树:数据库系统使用来提高访问辅助存储设备上的数据。一般通过优化手段使节点大小和辅助存储设备的块大小保持一致。

5、AVL树旋转:旋转分为LL旋转、LR旋转、RR旋转、RL旋转。任何平衡因子变为+-2时,重新向下平衡。
总结为两步:
(1)把长分支转换到最左侧,或最右侧
(2)从儿子节点往短的那边折
图中最底层的节点也可以是红圈的位置,它影响平衡调整
这里写图片描述
6、AVL树函数实现
(1)数据结构

//AVL树节点,BIT_TREE_NODE树节点的*data指向这个节点
typedef struct AvlNode_{
    void *data;//节点存储的具体内容
    int hidden;//0代表该节点不在树中
    int factor;//平衡因子,表示该节点子树左右的倾斜程度
}AvlNode;

(2)LL旋转和LR旋转

//调整tree树,node为返回变换后的root点,一般每插一个节点都会调整一次,不会出现超过+-2的情况
//LL旋转:节点*node的左叶的左叶重,*node -2,只有root节点和其左叶节点要变
//root节点的左叶变为,左叶的右叶;左叶变为root,其右叶为原root

//LR:节点*node的左叶的右叶重,*node -2,root节点、左子叶、左左子叶的右子叶(孙子叶)要变
static void rotate_left(BisTree *tree, BiTreeNode **node)
{
    BiTreeNode *left, *grandchild;
    left = bittree_left(*node);
    //LL旋转
    if(((AvlNode *)bittree_left(left))->factor == AVL_LFT_HEAVY)
    {
        bittree_left(*node) = bittree_right(left);
        bittree_right(left) = *node;
        ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
        *node = left;
    }

    //LR旋转
    else
    {
        grandchild = bittree_right(left);

        //左叶的右子树为,孙子的左子树
        bittree_right(left) = bittree_left(grandchild);
        //孙子的左子树为,原左叶
        bittree_left(grandchild) = left;
        //root节点的左叶为,孙子的右叶
        bittree_left(*node) =bittree_right(grandchild);
        //孙子右为,原root
        bittree_right(grandchild) = *node;

        //调整权重,孙子肯定平衡,孙子之前的左偏、右偏决定,父和左节点的平衡性
        switch(((AvlNode *)bittree_left(grandchild))->factor)
        {
            case AVL_LFT_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY;
                ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
                break;
            case AVL_REG_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(left))->factor = AVL_LFT_HEAVY;
                break;
            case AVL_BALANCED:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
                break;  

        }
        ((AvlNode *)bittree_data(grandchild))->factor = AVL_BALANCED;
        *node = grandchild;
    }
}

(3)RR、RL旋转

static void rotate_right(BiTreeNode **node)
{
    BiTreeNode *right, *grandchild;
    right = bittree_right(*node);
    if(((AvlNode *)bittree_right(right))->factor == AVL_REG_HEAVY)
    {
        bittree_right(*node) = bittree_left(right);
        bittree_left(right) = *node;
        ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
        *node = right;
    }
    else
    {
        grandchild = bittree_left(right);
        bittree_left(right) = bittree_right(grandchild);
        bittree_right(grandchild) = right;
        bittree_right(*node) =bittree_left(grandchild);
        bittree_left(grandchild) = *node;

        switch(((AvlNode *)bittree_left(grandchild))->factor)
        {
            case AVL_LFT_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY;
                ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
                break;
            case AVL_REG_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(right))->factor = AVL_LFT_HEAVY;
                break;
            case AVL_BALANCED:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
                break;  

        }
        ((AvlNode *)bittree_data(grandchild))->factor = AVL_BALANCED;
        *node = grandchild;
    }
}

(4)删掉树结构:包括删掉node的左子树,原树节点*data指向的AVL节点,AVL节点*data指向的数据,若node=NULL,则删除整个树

static void destroy_left(BisTree *tree, BiTreeNode *node)
{
    BiTreeNode **position;
    if(tree->size == 0)
        return;

    //如果node等于NULL则从头节点开始删掉 
    if(node == NULL)
        position = &tree->root;
    else
        position = &node->left;
    if(*position != NULL)
    {
        //如果tree已经没有子叶,则destroy_left,destroy_right直接返回,继续执行下面的删除该节点
         destroy_left(tree, *position);
         destroy_right(tree, *position);

         if(tree->destroy != NULL)
         {
            tree->destroy(((AvlNode *)bittree_data(position)->data)->data);
        } 
        free((*position)->data);
        free(*position);
        *position = NULL;
        tree->size--;
    }
    return;
}

static void destroy_right(BisTree *tree, BiTreeNode *node)
{
    BiTreeNode **position;
    if(tree->size == 0)
        return;

    //如果node等于NULL则从头节点开始删掉 
    if(node == NULL)
        position = &tree->root;
    else
        position = &node->right;
    if(*position != NULL)
    {
         destroy_left(tree, *position);
         destroy_right(tree, *position);

         if(tree->destroy != NULL)
         {
            tree->destroy(((AvlNode *)bittree_data(position)->data)->data);
        } 
        free((*position)->data);
        free(*position);
        *position = NULL;
        tree->size--;
    }
    return;
}

(5)向节点插入子节点,要考虑左插还是右插,是否需要旋转

//*node==NULL表示插入第一个节点
static int insert(BisTree *tree, BiTreeNode **node, const void *data, int *balanced)
{
    AvlNode *avl_data;
    int cmpval, retval;//cmpval是节点数据比较的结果,retval是返回的错误类型
    if(*node == NULL)
    {
        if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL)
            return -1;
        avl_data->factor = AVL_BALANCED;
        avl_data->hidden = 0;
        avl_data->data = (void *)data;
        return bittree_ins_left(tree, *node, avl_data); 
    }
    else
    {
        //比较数据大小决定往右边插还是往左边插 
        cmpval = tree->compare(data, ((AvlNode *)bittree_data(*node))->data);
        //判断大小,递归到最底层插入
        if(cmpval < 0)
        {
            if(bittree_left(*node) == NULL)
            {
                if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL)
                        return -1;
                avl_data->factor = AVL_BALANCED;
                avl_data->hidden = 0;
                avl_data->data = (void *)data;

                if(bittree_ins_left(tree, *node, avl_data) != 0)
                    return -1;

                //在最底层插入后让*balance=0,才可进行旋转,只需要旋转最下面一颗不平衡的树
                *balance = 0;
            }
            else
            {
                if((retval = insert(tree, &bittree_left(*node), data, balance)) != 0)
                    return retval;
            }
            if(!(*balanced))
            {
            //从插入节点的父节点开始,判断平衡,再到爷爷节点,只有这两层(除新插入的,最底的两层)需要判断
                switch (((AvlNode *)bittree_data(*node))->factor)
                {
                    case AVL_LFT_HEAVY:
                        rotate_left(node);
                        *balanced = 1;
                        break; 

                    //本来平衡左插后左偏 
                    case AVL_BALANCED:
                        ((AvlNode *)bittree_data(*node))->factor = AVL_LFT_HEAVY; 
                        break; 
                    case AVL_REG_HEAVY:
                        ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
                        *balanced = 1;
                        break; 
                }
            }
        }
        else if(cmpval > 0)
        {
            //到最底层才能插入
            if(bittree_right(*node) == NULL)
            {
                if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL)
                        return -1;
                avl_data->factor = AVL_BALANCED;
                avl_data->hidden = 0;
                avl_data->data = (void *)data;

                if(bittree_ins_right(tree, *node, avl_data) != 0)
                    return -1;

                //*balance表示是否到达最底层,没到最底层的父树*balance都为1
                *balance = 0;
            }
            else
            {
                if((retval = insert(tree, &bittree_right(*node), data, balance)) != 0)
                    return retval;
            }
            if(!(*balanced))
            {
            //现在是要往左边插入
                switch (((AvlNode *)bittree_data(*node))->factor)
                {
                    本来就左偏,再左插就要旋转,递归旋转
                    case AVL_REG_HEAVY:
                        rotate_right(node);
                        *balanced = 1;
                        break; 

                    //本来平衡右插后右偏 
                    case AVL_BALANCED:
                        ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY; 
                        break; 
                    case AVL_LFT_HEAVY:
                        ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
                        *balanced = 1;
                        break; 
                }
            }
        }
        //cmpval==0,即和*node节点数据相等 
        else
        {   //为了防止原数节点指向的数据和新加的相同,但是空间数据不同 
            if(!((AvlNode *)bittree_data(*node))->hidden)
                return 1;
            else
            {
                if(tree->destroy != NULL)
                {
                    tree->destroy(((AvlNode *)bittree_data(*node))->data);
                }
                ((AvlNode *)bittree_data(*node))->data = (void *)data;
                ((AvlNode *)bittree_data(*node))->hidden = 0;
                *balanced = 1;
            } 
        } 
    }
    return 0;
}

(6)标记节点是否已经在树中

//node是开始比较的节点
static int hide(BisTree *tree, BiTreeNode *node, const void *data)
{
    int cmpval, retval;

    //已经找到底 
    if(node == NULL)
    {
        return -1;
    }

    cmpval = tree->compare(data, ((AvlNode *)bittree_data(*node))->data);
    if(cmpval < 0)
    {
        retval = hide(tree, bittree_left(node), data);
    }

    else if(cmpval > 0)
    {
        retval = hide(tree, bittree_right(node), data);
    }
    else
    {
        ((AvlNode *)bittree_data(*node))->hidden = 1;
        retval = 0;
    } 
    return retval;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值